package main

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"net/http"
	"os"
	"strings"
	"time"

	"github.com/gorilla/mux"
	"github.com/linclaus/stock/pkg/cache"

	"github.com/linclaus/stock/pkg/channel"
	"github.com/linclaus/stock/pkg/grafana"

	"github.com/linclaus/stock/pkg/api"
	"github.com/linclaus/stock/pkg/model"
	"github.com/linclaus/stock/pkg/prometheus"

	"github.com/linclaus/stock/pkg/common/util"
	"github.com/prometheus/client_golang/prometheus/promhttp"
)

func main() {
	fmt.Println("Grafana-Daemon Started")
	var port string
	// Set Args
	flag.StringVar(&port, "port", "8081", "The address of stock APP")
	flag.StringVar(&api.STOCK_FILE_PATH, "stockPath", "/home/linclaus/stock/config/stock/", "The code file path")
	flag.StringVar(&prometheus.PROMETHEUS_HOST, "prometheusHost", "http://prometheus:9090", "Prometheus Host")
	flag.StringVar(&grafana.GrafanaArgs.GrafanaVer, "grafanaVersion", "5.x", "The Grafana version")
	flag.StringVar(&grafana.GrafanaArgs.GrafanaAddr, "grafanaAddr", "http://localhost:80", "The Grafana Address")
	flag.StringVar(&grafana.GrafanaArgs.GrafanaAdminUser, "grafanaUser", "admin", "The Grafana User")
	flag.StringVar(&grafana.GrafanaArgs.GrafanaAdminPass, "grafanaPass", "GS2018niu!888", "The Grafana Password")
	flag.Parse()

	codes := initCodeSet()
	r := mux.NewRouter()
	r.Handle("/metrics", promhttp.Handler())
	go http.ListenAndServe(":"+port, r)

	channel.Init()
	util.SetByCodes(codes.List(), cache.StockMap)
	//Init Grafana
	grafana.GrafanaArgs.PrometheusAddr = prometheus.PROMETHEUS_HOST
	grafana.GrafanaArgs.DataSourceName = "Prometheus"
	if err := grafana.Initialize(grafana.GrafanaArgs); err != nil {
		fmt.Print(err)
		return
	}
	grafana.CreateBasicDashboard("Metrics", "Stock", "stock")
	grafana.CreateBasicDashboard("Metrics", "Grafana-daemon", "grafana-daemon")
	grafana.CreateBasicDashboard("Metrics", "Prometheus", "prometheus")
	grafana.CreateBasicDashboard("Metrics", "Alertmanager", "alertmanager")
	grafana.CreateBasicDashboard("Metrics", "Grafana", "grafana")

	go grafana.CreateDashboardByStockMap(cache.StockMap)

	if err := grafana.CreateCustomDashboard("Aggregation", "上证指数成交量", "stock_trade_volume_total{code=\"sh000001\"}", "graph"); err != nil {
		fmt.Println(err)
	}
	if err := grafana.CreateCustomDashboard("Aggregation", "深证成指成交量", "stock_trade_volume_total{code=\"sz399001\"}", "graph"); err != nil {
		fmt.Println(err)
	}
	if err := grafana.CreateCustomDashboard("Aggregation", "当前涨停数", "count(10.1>stock_increase_gauge>9.9)", "graph"); err != nil {
		fmt.Println(err)
	}
	if err := grafana.CreateCustomDashboard("Aggregation", "当前跌停数", "count(-10.1<stock_increase_gauge<-9.9)", "graph"); err != nil {
		fmt.Println(err)
	}
	if err := grafana.CreateCustomDashboard("Aggregation", "股票涨跌幅分布直方图", "idelta(stock_increase_histogram_bucket{}[10d])", "bar"); err != nil {
		fmt.Println(err)
	}
	if err := grafana.CreateCustomDashboard("Aggregation", "股票涨跌幅分布热力图", "idelta(stock_increase_histogram_bucket{}[10d])", "heatmap"); err != nil {
		fmt.Println(err)
	}
	fmt.Println("Grafana-Daemon Ended")
	ticker := time.NewTicker(time.Second * time.Duration(60))
	for {
		select {
		case <-ticker.C:
			createAggregateIncreaseDashboard()
			createAggregateDecreaseDashboard()
			createAggregate10IncreaseDashboard()
			createAggregate10DecreaseDashboard()
		}
	}
}

func createAggregateIncreaseDashboard() {
	codes := prometheus.QueryPrometheusForCodes("9.9<(max_over_time(stock_increase_gauge[10m])<10.1)%20and%20idelta(stock_increase_gauge[5m])==0")
	if len(codes) > 0 {
		cstr := strings.Join(codes, "|")
		expr := fmt.Sprintf("stock_increase_gauge{code=~\"%s\"}", cstr)
		if err := grafana.CreateCustomDashboard("Aggregation", "当前涨停个股", expr, "graph"); err != nil {
			fmt.Println(err)
		}
	}
}

func createAggregateDecreaseDashboard() {
	codes := prometheus.QueryPrometheusForCodes("-10.1<(min_over_time(stock_increase_gauge[10m])<-9.9)%20and%20idelta(stock_increase_gauge[5m])==0")
	if len(codes) > 0 {
		cstr := strings.Join(codes, "|")
		expr := fmt.Sprintf("stock_increase_gauge{code=~\"%s\"}", cstr)
		if err := grafana.CreateCustomDashboard("Aggregation", "当前跌停个股", expr, "graph"); err != nil {
			fmt.Println(err)
		}
	}
}

func createAggregate10IncreaseDashboard() {
	codes := prometheus.QueryPrometheusForCodes("-10.1<min_over_time(stock_increase_gauge[10m])<-9.9%20and%20stock_increase_gauge>-9")
	if len(codes) > 0 {
		cstr := strings.Join(codes, "|")
		expr := fmt.Sprintf("stock_increase_gauge{code=~\"%s\"}", cstr)
		if err := grafana.CreateCustomDashboard("Aggregation", "过去十分钟处于跌停但现涨了1%", expr, "graph"); err != nil {
			fmt.Println(err)
		}
	}
}

func createAggregate10DecreaseDashboard() {
	codes := prometheus.QueryPrometheusForCodes("10.1>max_over_time(stock_increase_gauge[10m])>9.9%20and%20stock_increase_gauge<9")
	if len(codes) > 0 {
		cstr := strings.Join(codes, "|")
		expr := fmt.Sprintf("stock_increase_gauge{code=~\"%s\"}", cstr)
		if err := grafana.CreateCustomDashboard("Aggregation", "过去十分钟处于涨停但现跌了1%", expr, "graph"); err != nil {
			fmt.Println(err)
		}
	}
}

func initCodeSet() *model.CodeSet {
	// Initial the monitor stock code
	file, err := os.OpenFile(api.STOCK_FILE_PATH+api.CODE_FILE_NAME, os.O_RDONLY|os.O_CREATE, 0666)
	if err != nil {
		fmt.Println("文件打开失败", err)
	}
	buf := bufio.NewReader(file)

	codeStr := ""
	for {
		codeByte, _, err := buf.ReadLine()
		if err == io.EOF {
			break
		}
		codeStr = codeStr + string(codeByte)
	}

	file.Close()
	codes := strings.Split(codeStr, ",")
	cs := model.NewCodeSet()
	if len(codes) == 0 || codes[0] == "" {
		codes = []string{"sh000001", "sz399001"}
		cs.AddSet(codes)
		api.StoreCodes(cs)
		return cs
	}
	cs.AddSet(codes)
	return cs
}
